/* Autore: Nicola Agosti */
/*
Scrivi un programma che utilizzando la struttura Prodotto (codice, nome, prezzo, quantità disponibile),
simuli la gestione di un magazzino e permetta di:
 - aggiungere i dati di un nuovo prodotto all'inventario del magazzino;
 - depositare un prodotto in magazzino (incrementarne la quantità);
 - prelevare un prodotto dal magazzino (decrementarne la quantità);
 - visualizzare inventario.
*/

#define _CRT_SECURE_NO_WARNINGS /* Necessario se utilizziamo Visual Studio */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_PRODOTTI 100 /* Costante utilizzata per dimensionare il vettore */
#define MAX_LUNG_CODICE 10 /* Lunghezza massima del codice del prodotto */
#define MAX_LUNG_NOME 20 /* Lunghezza massima del nome del prodotto */
#define MAX_LUNG_STRINGA 100 /* Lunghezza massima di una stringa generica */

/* Definizione della struttura "Prodotto" */
/*
L'istruzione "typedef" viene utilizzata per creare un "alias" (associare un nuovo nome) ad un 
tipo di dato o a una struttura (nel caso delle strutture è un modo comodo per non dover sempre ripetere
la parola "struct" per definire una variabile di tipo struttura.
Esempio:
 - typedef unsigned int uint;
 - typedef struct punto mioPunto;
*/
typedef struct
{
	char codice[MAX_LUNG_CODICE + 1];
	char nome[MAX_LUNG_NOME + 1];
	float prezzo;
	int qtyDisponibile;
} prodotto;

/* Prototipi delle funzioni */
void myfgets(char[], int); /* Procedura che elimina l'eventuale "\n" al termine della stringa letta con la fgets */
void aggiungiNuovoProdotto(prodotto[], int*); /* Procedura che aggiunge i dati di un nuovo prodotto all'inventario del magazzino */
int cercaProdotto(char[], prodotto[], int); /* Funzione che cerca il codice del prodotto in magazzino */
void depositareProdotto(prodotto[], int); /* Procedura che deposita (ne aumenta la quantità) un prodotto in magazzino */
void prelevareProdotto(prodotto[], int); /* Procedura che preleva (ne riduce la quantità) un prodotto dal magazzino */
void stampaInventario(prodotto[], int); /* Procedura che stampa a video l'inventario del magazzino */

int main()
{
	/* Dichiaro un vettore di tipo "struct prodotti" che conterrà le informazioni dei prodotti contenulti nel magazzino */
	prodotto magazzino[MAX_PRODOTTI];
	int numProdottiInMagazzino = 0;
	
	char scelta[MAX_LUNG_STRINGA + 1];

	/* MENU' */
	/*
	do... while: è l'ultima tipologia di costrutto iterativo ed è l'unico di tipo post-condizionale,
	cioè è l'unico ciclo in cui la condizione viene valutata alla fine del blocco di codice interno al ciclo.
	Si usa quando il blocco di codice contenuto nel ciclo deve essere eseguito almeno una volta,
	come nel caso dei menù.
	*/
	do
	{
		printf("/*** MAGAZZINO ***/");
		printf("\n1) Aggiungi un nuovo prodotto");
		printf("\n2) Deposita un prodotto");
		printf("\n3) Preleva un prodotto");
		printf("\n4) Stampa l\'inventario");
		printf("\n0) Esci");
		printf("\nInserisci la scelta: ");
		myfgets(scelta, MAX_LUNG_STRINGA + 1);

		switch (scelta[0])
		{
		case '0':
			break;

		case '1':
			aggiungiNuovoProdotto(magazzino, &numProdottiInMagazzino);
			break;

		case '2':
			depositareProdotto(magazzino, numProdottiInMagazzino);
			break;

		case '3':
			prelevareProdotto(magazzino, numProdottiInMagazzino);
			break;

		case '4':
			stampaInventario(magazzino, numProdottiInMagazzino);
			break;

		default:
			printf("\nERRORE: scelta non valida!\n\n");
		}

	} while (scelta[0] != '0');

	return 0;
}

/* Procedura che elimina l'eventuale "\n" al termine della stringa letta con la fgets */
void myfgets(char str[], int maxCaratteri)
{
	/* Leggo la stringa */
	fgets(str, maxCaratteri, stdin);

	/* Elimino il "\n" finale se è presente */
	if (str[strlen(str) - 1] == '\n')
	{
		str[strlen(str) - 1] = '\0';
	}
}

/* Procedura che aggiunge i dati di un nuovo prodotto all'inventario del magazzino */
void aggiungiNuovoProdotto(prodotto magazzino[], int *numProdottiInMagazzino)
{
	char str[MAX_LUNG_STRINGA + 1];

	/* Verifico che ci sia ancora spazio in magazzino */
	if (*numProdottiInMagazzino >= MAX_PRODOTTI)
	{
		/* Il magazzino è pieno */
		printf("\nERRORE: impossibile aggiungere il nuovo prodotto, il magazzino e\' pieno!\n\n");
		return;
	}

	/* Chiedo all'utente di inserire i dati del prodotto */
	printf("\nInserisci il codice del prodotto: ");
	myfgets(magazzino[*numProdottiInMagazzino].codice, MAX_LUNG_CODICE + 1);
	printf("Inserisci il nome del prodotto: ");
	myfgets(magazzino[*numProdottiInMagazzino].nome, MAX_LUNG_NOME + 1);
	printf("Inserisci il prezzo del prodotto: ");
	myfgets(str, MAX_LUNG_STRINGA + 1);
	sscanf(str, "%f", &magazzino[*numProdottiInMagazzino].prezzo);
	printf("Inserisci la quantita\' iniziale del prodotto: ");
	myfgets(str, MAX_LUNG_STRINGA + 1);
	sscanf(str, "%d", &magazzino[*numProdottiInMagazzino].qtyDisponibile);

	/* Verifico che il prodotto (il suo codice) non sia già presente in magazzino */
	if (cercaProdotto(magazzino[*numProdottiInMagazzino].codice, magazzino, *numProdottiInMagazzino) != -1)
	{
		/* Il prodotto è già presente in magazzino */
		printf("\nERRORE: impossibile aggiungere il nuovo prodotto perche\' il codice e\' gia\' presente in magazzino!\n\n");
		return;
	}

	/* Verifico che i dati del prodotto siano corretti */
	if (strlen(magazzino[*numProdottiInMagazzino].codice) < 1
		|| strlen(magazzino[*numProdottiInMagazzino].nome) < 1
		|| magazzino[*numProdottiInMagazzino].prezzo <= 0
		|| magazzino[*numProdottiInMagazzino].qtyDisponibile < 0)
	{
		/* I dati del prodotto non sono corretti */
		printf("\nERRORE: impossibile aggiungere il nuovo prodotto perche\' le informazioni NON sono corrette!\n\n");
		return;
	}

	/* Aggiungo il nuovo prodotto */
	(*numProdottiInMagazzino)++;

	printf("\n");
}

/* Funzione che cerca il codice del prodotto in magazzino */
/* Ritorna la posizione del prodotto nel vettore o "-1" se il prodotto non è presente */
int cercaProdotto(char codice[], prodotto magazzino[], int numProdottiInMagazzino)
{
	int i;

	/* Cerco il prodotto */
	for (i = 0; i < numProdottiInMagazzino; i++)
	{
		/* Prodotto tovato? */
		if (strcmp(magazzino[i].codice, codice) == 0)
		{
			/* Trovato! */
			return i;
		}
	}

	/* Il prodotto non è presente in magazzino */
	return -1;
}

/* Procedura che deposita (ne aumenta la quantità) un prodotto in magazzino */
void depositareProdotto(prodotto magazzino[], int numProdottiInMagazzino)
{
	char codice[MAX_LUNG_CODICE + 1], str[MAX_LUNG_STRINGA];
	int posProdotto, qtyDaDepositare;

	/* Chiedo all'utente di inserire il codice del prodotto */
	printf("\nInserisci il codice del prodotto da depositare: ");
	myfgets(codice, MAX_LUNG_CODICE + 1);

	/* Cerco il prodotto in magazzino */
	posProdotto = cercaProdotto(codice, magazzino, numProdottiInMagazzino);

	/* Prodotto presente in magazzino? */
	if (posProdotto == -1)
	{
		printf("ERRORE: il prodotto non e\' presente in magazzino!\n\n");
		return;
	}

	/* Chiedo all'utente quante unità vuole depositare */
	printf("Inserisci il numero di unita\' di prodotto da depositare: ");
	myfgets(str, MAX_LUNG_STRINGA + 1);
	sscanf(str, "%d", &qtyDaDepositare);

	/* Quantità corretta? */
	if (qtyDaDepositare < 1)
	{
		printf("ERRORE: la quantita\' di prodotto da depositare in magazzino non e\' corretta!\n\n");
		return;
	}

	/* Aggiorno la quantità di prodotto */
	magazzino[posProdotto].qtyDisponibile += qtyDaDepositare;
	printf("Quantita\' disponibile dopo il deposito: %d", magazzino[posProdotto].qtyDisponibile);
	printf("\n\n");
}

/* Procedura che preleva (ne riduce la quantità) un prodotto dal magazzino */
void prelevareProdotto(prodotto magazzino[], int numProdottiInMagazzino)
{
	char codice[MAX_LUNG_CODICE + 1], str[MAX_LUNG_STRINGA];
	int posProdotto, qtyDaPrelevare;

	/* Chiedo all'utente di inserire il codice del prodotto */
	printf("\nInserisci il codice del prodotto da prelevare: ");
	myfgets(codice, MAX_LUNG_CODICE + 1);

	/* Cerco il prodotto in magazzino */
	posProdotto = cercaProdotto(codice, magazzino, numProdottiInMagazzino);

	/* Prodotto presente in magazzino? */
	if (posProdotto == -1)
	{
		printf("ERRORE: il prodotto non e\' presente in magazzino!\n\n");
		return;
	}

	/* Chiedo all'utente quante unità vuole prelevare */
	printf("Inserisci il numero di unita\' di prodotto da prelevare: ");
	myfgets(str, MAX_LUNG_STRINGA + 1);
	sscanf(str, "%d", &qtyDaPrelevare);

	/* Quantità corretta? */
	if (qtyDaPrelevare < 1)
	{
		printf("ERRORE: la quantita\' di prodotto da prelevare dal magazzino non e\' corretta!\n\n");
		return;
	}

	/* La richiesta può essere soddisfatta? */
	if (magazzino[posProdotto].qtyDisponibile < qtyDaPrelevare)
	{
		printf("ERRORE: la quantita\' di prodotto in magazzino non e\' sufficiente a soddisfare la richiesta inserita!\n\n");
		return;
	}

	/* Aggiorno la quantità di prodotto */
	magazzino[posProdotto].qtyDisponibile -= qtyDaPrelevare;
	printf("Quantita\' disponibile dopo il deposito: %d", magazzino[posProdotto].qtyDisponibile);
	printf("\n\n");
}

/* Procedura che stampa a video l'inventario del magazzino */
void stampaInventario(prodotto magazzino[], int numProdottiInMagazzino)
{
	int i;

	/* Intestazione */
	/*
	N.B. Nella "printf" il numero tra il "%" e la "s" indica la dimensione, in caratteri, dello spazio
	riservato alla stringa eventualmente riempito con gli spazi.
	N.B. Nella "printf" il "-" dopo il "%" indica che il testo verrà allineato a destra rispetto allo spazio
	riservato alla stringa.
	*/
	printf("\n|----------------------------------------------------|");
	printf("\n|              INVENTARIO DEL MAGAZZINO              |");
	printf("\n|----------------------------------------------------|");
	printf("\n| %-10s | %-20s | %6s | %5s |", "CODICE", "NOME", "PREZZO", "QTY");
	printf("\n|----------------------------------------------------|");

	/* Scorro l'inventario del magazzino */
	for (i = 0; i < numProdottiInMagazzino; i++)
	{
		/* Visualizzo i dati del prodotto */
		printf("\n| %-10s | %-20s | %6.2f | %5d |", magazzino[i].codice, magazzino[i].nome, magazzino[i].prezzo, magazzino[i].qtyDisponibile);
	}

	/* Chiusura della tabella */
	printf("\n|----------------------------------------------------|");

	printf("\n\n");
}